package com.xyazm.order.service.impl;

import com.xyazm.common.constants.RedisLockKeyConstants;
import com.xyazm.common.enums.OrderStatusChangeEnum;
import com.xyazm.common.enums.OrderStatusEnum;
import com.xyazm.common.redis.RedisLock;
import com.xyazm.order.dao.AfterSaleRefundDAO;
import com.xyazm.order.dao.OrderCancelScheduledTaskDAO;
import com.xyazm.order.dao.OrderInfoDAO;
import com.xyazm.order.domain.dto.AfterSaleStateMachineDTO;
import com.xyazm.order.domain.entity.AfterSaleRefundDO;
import com.xyazm.order.domain.entity.OrderCancelScheduledTaskDO;
import com.xyazm.order.domain.entity.OrderInfoDO;
import com.xyazm.order.domain.mq.ActualRefundDTO;
import com.xyazm.order.domain.param.CancelOrderAssembleParam;
import com.xyazm.order.domain.param.CancelOrderParam;
import com.xyazm.order.domain.param.PayRefundCallbackParam;
import com.xyazm.order.domain.param.ReceiveCustomerAfterSaleParam;
import com.xyazm.order.enums.AfterSaleStateChangeEnum;
import com.xyazm.order.enums.AfterSaleStatusEnum;
import com.xyazm.order.exception.OrderBizException;
import com.xyazm.order.exception.OrderErrorCodeEnum;
import com.xyazm.order.service.IAfterSaleService;
import com.xyazm.order.statemachine.AfterSaleStateMachine;
import com.xyazm.order.statemachine.OrderStateMachine;
import com.xyazm.order.statemachine.StateMachineFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class AfterSaleServiceImpl implements IAfterSaleService {


    @Autowired
    private OrderInfoDAO orderInfoDAO;
    @Autowired
    private RedisLock redisLock;
    @Autowired
    private AfterSaleRefundDAO afterSaleRefundDAO;
    @Autowired
    private OrderCancelScheduledTaskDAO orderCancelScheduledTaskDAO;
    @Autowired
    private StateMachineFactory stateMachineFactory;


    @Override
    public void cancelOrder(CancelOrderParam param) {
        //  售后状态机 -> 取消订单
        OrderStateMachine orderStateMachine = stateMachineFactory.getOrderStateMachine(OrderStatusEnum.CANCELLED);
        // 订单取消 70 已取消 -> 70 已取消
        orderStateMachine.fire(OrderStatusChangeEnum.ORDER_CANCEL, param);
    }

    @Override
    public void processCancelOrder(CancelOrderAssembleParam cancelOrderAssembleParam) {
        AfterSaleStateMachineDTO afterSaleStateMachineDTO = new AfterSaleStateMachineDTO();
        afterSaleStateMachineDTO.setCancelOrderAssembleParam(cancelOrderAssembleParam);
        // 售后状态机 操作 取消订单时记录售后信息
        AfterSaleStateMachine afterSaleStateMachine = stateMachineFactory.getAfterSaleStateMachine(AfterSaleStatusEnum.UN_CREATED);
        // 取消订单 0 未创建 -> 20 审核通过
        afterSaleStateMachine.fire(AfterSaleStateChangeEnum.CANCEL_ORDER, afterSaleStateMachineDTO);
    }

    @Override
    public void refundMoney(ActualRefundDTO actualRefundDTO) {
        AfterSaleStateMachineDTO afterSaleStateMachineDTO = new AfterSaleStateMachineDTO();
        afterSaleStateMachineDTO.setActualRefundDTO(actualRefundDTO);
        // 售后状态机 操作 实际退款中通过更新售后信息
        AfterSaleStateMachine afterSaleStateMachine = stateMachineFactory.getAfterSaleStateMachine(AfterSaleStatusEnum.REVIEW_PASS);
        // 退款中 20 审核通过 -> 40 退款中
        afterSaleStateMachine.fire(AfterSaleStateChangeEnum.REFUNDING, afterSaleStateMachineDTO);
    }

    @Override
    public void payRefundCallback(PayRefundCallbackParam param) {
        AfterSaleStateMachineDTO afterSaleStateMachineDTO = new AfterSaleStateMachineDTO();
        afterSaleStateMachineDTO.setPayRefundCallbackParam(param);
        // 售后状态机 操作 支付回调退款成功 更新售后信息
        AfterSaleStateMachine afterSaleStateMachine = stateMachineFactory.getAfterSaleStateMachine(AfterSaleStatusEnum.REFUNDING);
        // 退款成功 40 退款中 -> 50 退款成功 默认退款成功 如果退款失败，在状态机内部有流转记录
        afterSaleStateMachine.fire(AfterSaleStateChangeEnum.REFUND_SUCCESS, afterSaleStateMachineDTO);
    }

    @Override
    public Long customerFindAfterSaleRefundInfo(ReceiveCustomerAfterSaleParam param) {
        String afterSaleId = param.getAfterSaleId();
        AfterSaleRefundDO afterSaleRefundDO = afterSaleRefundDAO.getOneByAfterSaleId(afterSaleId);
        if (afterSaleRefundDO == null) {
            throw new OrderBizException(OrderErrorCodeEnum.AFTER_SALE_REFUND_ID_IS_NULL);
        }
        return afterSaleRefundDO.getId();
    }

    @Override
    public void verifyBeforeOrderCancellation(String orderId) {
        // 分布式锁(与预支付、订单支付回调加的是同一把锁)
        String key = RedisLockKeyConstants.ORDER_PAY_KEY + orderId;
        boolean lock = redisLock.tryLock(key);
        if (!lock) {
            throw new OrderBizException(OrderErrorCodeEnum.ORDER_CANNOT_OPERATED_IN_MULTIPLE_PLACES);
        }

        try {
            // 查询订单实时状态
            OrderInfoDO orderInfoDO = orderInfoDAO.getByOrderId(orderId);
            // 参数和幂等校验，如果校验失败 本次流程直接结束
            if (!checkParamIdempotent(orderInfoDO)) {
                return;
            }
            // 组装调用执行取消订单接口参数
            CancelOrderParam cancelOrderParam = buildCancelOrderParam(orderInfoDO);
            // 执行取消订单
            cancelOrder(cancelOrderParam);
            // 删除任务记录
            orderCancelScheduledTaskDAO.remove(orderInfoDO.getOrderId());
        } finally {
            // 释放分布式锁
            redisLock.unlock(key);
        }
    }

    /**
     * 组装调用执行取消订单接口参数
     * @author xuyou
     * 2023-02-23 22:31
    */
    private CancelOrderParam buildCancelOrderParam(OrderInfoDO orderInfoDO) {
        CancelOrderParam cancelOrderParam = new CancelOrderParam();
        cancelOrderParam.setOrderId(orderInfoDO.getOrderId());
        cancelOrderParam.setBusinessIdentifier(orderInfoDO.getBusinessIdentifier());
        cancelOrderParam.setCancelType(orderInfoDO.getOrderType());
        cancelOrderParam.setUserId(orderInfoDO.getUserId());
        cancelOrderParam.setOrderType(orderInfoDO.getOrderType());
        cancelOrderParam.setOrderStatus(orderInfoDO.getOrderStatus());
        return cancelOrderParam;
    }

    /**
     * 订单超时未支付取消订单,校验参数和幂等校验
     * @author xuyou
     * 2023-02-23 22:21
    */
    private boolean checkParamIdempotent(OrderInfoDO orderInfoDO) {
        //  参数校验
        if (orderInfoDO == null) {
            return false;
        }

        //  幂等校验 当前订单的任务记录不存在 结束流程
        OrderCancelScheduledTaskDO orderCancelScheduledTaskDO = orderCancelScheduledTaskDAO.getByOrderId(orderInfoDO.getOrderId());
        if (orderCancelScheduledTaskDO == null) {
            return false;
        }

        //  订单非"已创建"状态,说明有了其他的操作,可以删除掉兜底记录  结束流程
        if (!OrderStatusEnum.CREATED.getCode().equals(orderInfoDO.getOrderStatus())) {
            // 删除任务记录
            orderCancelScheduledTaskDAO.remove(orderInfoDO.getOrderId());
            return false;
        }

        //  如果  当前时间 > 订单实际支付截止时间 返回true, 否则false
        return System.currentTimeMillis() > orderInfoDO.getExpireTime().getTime();
    }

}
